package com.yygo.webapp.controller.loanrequest;

import com.yygo.Constants;
import com.yygo.configentity.action.Action;
import com.yygo.configentity.attachment.RoleAttachment;
import com.yygo.configentity.feedback.RoleFeedback;
import com.yygo.model.*;
import com.yygo.model.enums.AuditCode;
import com.yygo.model.enums.FeedbackStatus;
import com.yygo.model.enums.Phase;
import com.yygo.model.enums.RequestStatus;
import com.yygo.service.*;
import com.yygo.util.StringUtil;
import com.yygo.webapp.controller.BaseFormController;
import org.apache.activemq.ScheduledMessage;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.jms.JmsException;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.core.MessageCreator;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestParam;

import javax.jms.*;
import javax.servlet.http.HttpServletRequest;
import java.security.Principal;
import java.util.*;

/**
 * Created by tiansha on 2015/7/4.
 */
public class BaseLoanRequestFormController extends BaseFormController {

    final static String ACTION_submitDraft = "submitDraft";
    final static String ACTION_bankCreditApprove = "bankCreditApprove";
    final static String ACTION_bankCreditDeny = "bankCreditDeny";
    final static String ACTION_bankGotoCA = "bankGotoCA";
    final static String ACTION_submitRequest = "submitRequest";
    final static String ACTION_bondRequestApprove = "bondRequestApprove";
    final static String ACTION_bondRequestDeny = "bondRequestDeny";
    final static String ACTION_ccApprove = "ccApprove";
    final static String ACTION_caApprove = "caApprove";
    final static String ACTION_caSaveCredit = "caSaveCredit";

    final static String ACTION_caBackDealer = "caBackDealer";
    final static String ACTION_caBackBank = "caBackBank";
    final static String ACTION_scaApprove = "scaApprove";
    final static String ACTION_scaBack = "scaBack";
    final static String ACTION_qualificationApprove = "qualificationApprove";
    final static String ACTION_qualificationBack = "qualificationBack";
    final static String ACTION_applyLoan = "applyLoan";
    final static String ACTION_cancelLoan = "cancelLoan";
    final static String ACTION_bondLoanApprove = "bondLoanApprove";
    final static String ACTION_bondLoanDeny = "bondLoanDeny";
    final static String ACTION_bookingApprove = "bookingApprove";
    final static String ACTION_bookingGotoBank = "bookingGotoBank";
    final static String ACTION_bookingCanPrepay = "bookingCanPrepay";
    final static String ACTION_bookingDeny = "bookingDeny";
    final static String ACTION_insuranceLoanApprove = "insuranceLoanApprove";
    final static String ACTION_insuranceConfirmCover = "insuranceConfirmCover";
    final static String ACTION_insuranceDenyCover = "insuranceDenyCover";
    final static String ACTION_insuranceUploadCover = "insuranceUploadCover";
    final static String ACTION_insuranceLoanBack = "insuranceLoanBack";
    final static String ACTION_bankLoanApprove = "bankLoanApprove";
    final static String ACTION_bankLoanBack = "bankLoanBack";
    final static String ACTION_bankLoaned = "bankLoaned";
    final static String ACTION_insuranceConfirmPolicy = "insuranceConfirmPolicy";
    final static String ACTION_insuranceUploadPolicy = "insuranceUploadPolicy";
    final static String ACTION_insurancePolicyBack = "insurancePolicyBack";
    final static String ACTION_caSaveAudit = "caSaveAudit";
    final static String ACTION_scaSaveAudit = "scaSaveAudit";
    final static String ACTION_batchReceive = "batchReceive";


    @Autowired
    protected RoleActionsConfigurer roleActionsConfigurer;

    @Autowired
    protected RoleViewsConfigurer roleViewsConfigurer;

    @Autowired
    protected RoleFeedbacksConfigurer roleFeedbacksConfigurer;

    @Autowired
    protected RoleAttachmentsConfigurer roleAttachmentsConfigurer;


    protected LoanRequestManager loanRequestManager;

    @Autowired
    public void setLoanRequestManager(@Qualifier("loanRequestManager") LoanRequestManager loanRequestManager) {
        this.loanRequestManager = loanRequestManager;
    }

    protected LoanProductManager loanProductManager;
    @Autowired
    public void setLoanProductManager(LoanProductManager loanProductManager) {
        this.loanProductManager = loanProductManager;
    }

    private RequestNumberManager requestNumberManager;
    @Autowired
    public void setRequestNumberManager(RequestNumberManager requestNumberManager) {
        this.requestNumberManager = requestNumberManager;
    }

    private ContractNumberManager contractNumberManager;
    @Autowired
    public void setContractNumberManager(ContractNumberManager contractNumberManager) {
        this.contractNumberManager = contractNumberManager;
    }

    @Autowired
    private ProvinceManager provinceManager;

    @Autowired VehicleBrandManager vehicleBrandManager;

    @Autowired
    protected BankManager bankManager;

    protected UserManager userManager;
    @Autowired
    public void setUserManager(UserManager userManager) {
        this.userManager = userManager;
    }

    @Autowired
    private JmsTemplate jmsTemplate;

    @Autowired
    private Destination destination;

    protected void transferStatus(LoanRequest loanRequest, RequestStatus status, Phase phase, User auditUser, Locale locale, User loggedUser, String role) {
        loanRequest.setStatus(status);
        loanRequest.setPhase(phase);
        loanRequest.setAuditDate(new Date());
        String readableStatus = getText("PHASE_".concat(phase.toString()), Locale.SIMPLIFIED_CHINESE);
        // add activity
        String activity = getText("loanRequest.activity.transferPhase", readableStatus, Locale.SIMPLIFIED_CHINESE);
        if (auditUser != null) {
            loanRequest.setAuditUser(auditUser);
            activity = getText("loanRequest.activity.transferPhaseAndOperator", new String[]{readableStatus, auditUser.getUsername()}, Locale.SIMPLIFIED_CHINESE);
        }
        Activity activityObj = new Activity(loggedUser.getUsername(), activity);
        activityObj.setRole(role);
        activityObj.setLoanRequest(loanRequest);
        loanRequest.getActivities().add(activityObj);

        // clean feedback
        for (Feedback feedback : loanRequest.getFeedbackList()) {
            feedback.setFeedbackStatus(FeedbackStatus.End);
        }
    }

    protected User getRandomUser(String role) {
        List<User> list = userManager.getUsersByRole(role);
        User user = getRandomUser(list);
        
        return user;
    }

    protected User getRandomUser(List<User> list) {
        User user = null;
        if (list.size() > 0) {
            Random random = new Random();
            int k = random.nextInt(list.size());

            user = list.get(k);
        }
        return user;
    }

    protected String getRequestNumber() {
        RequestNumberGenerator generator = new RequestNumberGenerator();
        generator = (RequestNumberGenerator)requestNumberManager.save(generator);
        long id = generator.getId();
        String f = "%08d";
        String number = String.format(f, id);
        return "A" + number;
    }

    protected String getContractNumber() {
        ContractNumberGenerator generator = new ContractNumberGenerator();
        generator = (ContractNumberGenerator)contractNumberManager.save(generator);
        long id = generator.getId();
        String f = "%08d";
        String number = String.format(f, id);
        return "C" + number;
    }

    /**************************************************************************************************************************************
        handle process flow and status transition  START
     **************************************************************************************************************************************/

    protected  void handleAction(Action action, LoanRequest loanRequest, Locale locale, User loggedUser) throws AccessDeniedException, IllegalAccessException {
        if (action.isSendback()) {
            loanRequest.setSendback(true);
        } else {
            loanRequest.setSendback(false);
        }

        boolean autoAudit = false;
        User auditUser = null;
        boolean isGrab = roleActionsConfigurer.isGrab(action.getToRole(), action.getToPhase());
        if (action.getName().equals("bookingCanPrepay")) { // only this action not change audit user
            auditUser = loanRequest.getAuditUser();
        } else if (action.isSendback()) {
            auditUser = getHistoryUser(loanRequest, action.getToRole());
        } else if (isGrab) {
            auditUser = null;
        } else if (action.getToRole().equals(Constants.Insurance_ROLE)) {
            if (action.isSlave()) {
                auditUser = loanRequest.getDealer().getSlaveProvider().getBondUser();
                if (loanRequest.getDealer().getSlaveProvider().isAutoAudit()) {
                    autoAudit = true;
                }
            } else if (action.isMaster()) {
                auditUser = loanRequest.getDealer().getMasterProvider().getBondUser();
            }
        } else if (action.getToRole().equals(Constants.Bond_USER_ROLE)) {
            auditUser = loanRequest.getDealer().getBond().getBondUser();
        } else if (!StringUtil.isBlankOrNull(action.getToRole())) {
            auditUser = getHistoryUser(loanRequest, action.getToRole());
        }
        transferStatus(loanRequest, RequestStatus.valueOf(action.getToStatus()), Phase.valueOf(action.getToPhase()), auditUser, locale, loggedUser, action.getFromRole());
        loanRequest.setAuditUser(auditUser);

        if (action.getToRole().equals(Constants.Bond_USER_ROLE)) {
            if (loanRequest.getDealer().getBond().isAutoAudit()) {
                autoAudit = true;
            }
        }

        if (autoAudit && !StringUtil.isBlankOrNull(action.getAutoAction()) && auditUser != null) {
            handleAction(action.getAutoAction(), loanRequest, locale, auditUser);
        }

    }

    protected void handleAction(String actionName, LoanRequest loanRequest, Locale locale, User auditUser) throws AccessDeniedException, IllegalAccessException {
        Action autoAction = getAction(loanRequest, auditUser, actionName);
        if (autoAction != null) {
            handleAction(autoAction, loanRequest, locale, auditUser);
        }
    }

    // dealer - draft -> bank
    /*protected void handleSubmitDraft(LoanRequest loanRequest, Locale locale, User loggedUser) throws AccessDeniedException {
        if (log.isDebugEnabled()) {
            log.debug("submit request draft " + loanRequest.getNumber());
        }

        if (loanRequest.getPhase() != Phase.draft || !(isDealer(loggedUser))) {
            throw new AccessDeniedException("You have no right to submit request");
        }
        loanRequest.setRequestDate(new Date());
        User bankUser = null;
        transferStatus(loanRequest, RequestStatus.bank_credit_audit, Phase.bank_credit_audit, bankUser, locale, loggedUser, Constants.DEALER_USER_ROLE);

        *//*if (loanRequest.getLoanProduct().getBank().isAutoAudit()) {
            bankUser = getRandomUser(bankManager.getUsers(loanRequest.getLoanProduct().getBank().getId()));
            handleBankApproveRequest(loanRequest, locale, bankUser);
        } else {
            loanRequest.setAuditUser(null); // bank to grab
        }*//*
    }*/

    // bank approve - credit audit -> dealer
    /*protected void handleBankApproveRequest(LoanRequest loanRequest, Locale locale, User loggedUser) throws AccessDeniedException {
        if (log.isDebugEnabled()) {
            log.debug("bank approve request " + loanRequest.getNumber());
        }

        if (!(loanRequest.getPhase() == Phase.bank_credit_audit) || !loanRequest.getAuditUser().hasRole(Constants.Bank_CREDIT_ROLE)) {
            throw new AccessDeniedException("You have no right to approve request");
        }

        loanRequest.setSendback(false);
        User auditUser = null;
        transferStatus(loanRequest, RequestStatus.dealer_submit, Phase.dealer_submit, auditUser, locale, loggedUser, Constants.Bank_USER_ROLE);
    }*/

    // bank approve - go to CA
    /*protected void handleBankGotoCARequest(LoanRequest loanRequest, Locale locale, User loggedUser) throws AccessDeniedException, IllegalAccessException {
        if (log.isDebugEnabled()) {
            log.debug("bank approve request " + loanRequest.getNumber());
        }

        if (!(loanRequest.getPhase() == Phase.bank_credit_audit) || !loanRequest.getAuditUser().hasRole(Constants.Bank_CREDIT_ROLE)) {
            throw new AccessDeniedException("You have no right to approve request");
        }

        loanRequest.setSendback(false);
        User auditUser = getHistoryUser(loanRequest, Constants.CA_ROLE);
        transferStatus(loanRequest, RequestStatus.loan_audit, Phase.ca_audit, auditUser, locale, loggedUser, Constants.Bank_CREDIT_ROLE);
    }*/

    // bank deny - credit audit -> denied
    /*protected void handleBankDenyRequest(LoanRequest loanRequest, Locale locale, User loggedUser) throws AccessDeniedException {
        if (log.isDebugEnabled()) {
            log.debug("bank deny request " + loanRequest.getNumber());
        }

        if (loanRequest.getPhase() != Phase.bank_credit_audit || !loanRequest.getAuditUser().hasRole(Constants.Bank_CREDIT_ROLE)) {
            throw new AccessDeniedException("You have no right to deny request");
        }

        loanRequest.setSendback(false);

        User auditUser = null;
        loanRequest.setDecideDate(new Date());
        transferStatus(loanRequest, RequestStatus.credit_denied, Phase.credit_denied, auditUser, locale, loggedUser, Constants.Bank_CREDIT_ROLE);
    }*/

    // dealer submit -> bond
    /*protected void handleSubmitRequest(LoanRequest loanRequest, Locale locale, User loggedUser) throws AccessDeniedException {
        if (log.isDebugEnabled()) {
            log.debug("submit request request " + loanRequest.getNumber());
        }

        if (loanRequest.getPhase() != Phase.dealer_submit || !(isDealer(loggedUser))) {
            throw new AccessDeniedException("You have no right to submit request");
        }

        loanRequest.setSendback(false);

        User auditUser = loanRequest.getDealer().getBond().getBondUser();
        transferStatus(loanRequest, RequestStatus.request_audit, Phase.bond_request_audit, auditUser, locale, loggedUser, Constants.DEALER_USER_ROLE);

        if (loanRequest.getDealer().getBond().isAutoAudit()) {
            handleBondApproveRequest(loanRequest, locale, auditUser);
        }
    }*/

    // bond approve -> cc
    /*protected void handleBondApproveRequest(LoanRequest loanRequest, Locale locale, User loggedUser) throws AccessDeniedException {
        if (log.isDebugEnabled()) {
            log.debug("bond company approve request " + loanRequest.getNumber());
        }

        if (loanRequest.getPhase() != Phase.bond_request_audit || !loanRequest.getAuditUser().hasRole(Constants.Bond_USER_ROLE)) {
            throw new AccessDeniedException("You have no right to approve request");
        }

        loanRequest.setSendback(false);

        User auditUser = null;
        transferStatus(loanRequest, RequestStatus.request_audit, Phase.cc_audit, auditUser, locale, loggedUser, Constants.Bond_USER_ROLE);
        loanRequest.setPhase(Phase.processing_rule);
        loanRequest.setStatus(RequestStatus.processing_rule);
        loanRequest.setAuditUser(null); // cc to grab
    }*/

    // bond deny
    /*protected void handleBondDenyRequest(LoanRequest loanRequest, Locale locale, User loggedUser) throws AccessDeniedException {
        if (log.isDebugEnabled()) {
            log.debug("bond company deny request " + loanRequest.getNumber());
        }

        if (loanRequest.getPhase() != Phase.bond_request_audit || !loanRequest.getAuditUser().hasRole(Constants.Bond_USER_ROLE)) {
            throw new AccessDeniedException("You have no right to deny request");
        }

        loanRequest.setSendback(false);

        User auditUser = null;
        loanRequest.setDecideDate(new Date());
        transferStatus(loanRequest, RequestStatus.request_denied, Phase.request_denied, auditUser, locale, loggedUser, Constants.Bond_USER_ROLE);
    }*/

    // cc -> ca
    /*protected void handlePboc(LoanRequest loanRequest, Locale locale, User loggedUser) throws AccessDeniedException {
        if (log.isDebugEnabled()) {
            log.debug("Finish PBOC request " + loanRequest.getNumber());
        }

        if (!loanRequest.getAuditUser().hasRole(Constants.CC_ROLE) || loanRequest.getPhase() != Phase.cc_audit) {
            throw new AccessDeniedException("You have no right to finish pboc request");
        }

        loanRequest.setSendback(false);

        User auditUser = null;
        TalkRecord talkRecord = new TalkRecord();
        talkRecord.setOperator(loggedUser.getUsername());
        talkRecord.setTime(new Date());
        talkRecord.setContent(loanRequest.getPbocComment());
        talkRecord.setLoanRequest(loanRequest);
        loanRequest.getTalkRecordList().add(talkRecord);
        transferStatus(loanRequest, RequestStatus.request_audit, Phase.ca_audit, auditUser, locale, loggedUser, Constants.CC_ROLE);
        loanRequest.setAuditUser(null); // ca to grab
    }*/

    // ca advice -> sca
    /*protected void handleAdviceLoan(LoanRequest loanRequest, Locale locale, User loggedUser) throws AccessDeniedException {
        if (log.isDebugEnabled()) {
            log.debug("Advice loan request " + loanRequest.getNumber());
        }

        if (!loanRequest.getAuditUser().hasRole(Constants.CA_ROLE) || loanRequest.getPhase() != Phase.ca_audit) {
            throw new AccessDeniedException("You have no right to advice loan request");
        }
        loanRequest.setSendback(false);
        User auditUser = null;
        transferStatus(loanRequest, RequestStatus.request_audit, Phase.sca_audit, auditUser, locale, loggedUser, Constants.CA_ROLE);
        loanRequest.setAuditUser(null); // sca to grab
    }*/

    // ca back -> dealer
    /*protected void handleCABackDealer(LoanRequest loanRequest, Locale locale, User loggedUser) throws AccessDeniedException {
        if (log.isDebugEnabled()) {
            log.debug("Advice loan request " + loanRequest.getNumber());
        }

        if (!loanRequest.getAuditUser().hasRole(Constants.CA_ROLE) || loanRequest.getPhase() != Phase.ca_audit) {
            throw new AccessDeniedException("You have no right to advice loan request");
        }
        loanRequest.setSendback(true);
        User auditUser = null;
        transferStatus(loanRequest, RequestStatus.dealer_submit, Phase.dealer_submit, auditUser, locale, loggedUser, Constants.CA_ROLE);
    }*/

    // ca back -> bank
    /*protected void handleCABackBank(LoanRequest loanRequest, Locale locale, User loggedUser) throws AccessDeniedException, IllegalAccessException {
        if (log.isDebugEnabled()) {
            log.debug("Advice loan request " + loanRequest.getNumber());
        }

        if (!loanRequest.getAuditUser().hasRole(Constants.CA_ROLE) || loanRequest.getPhase() != Phase.ca_audit) {
            throw new AccessDeniedException("You have no right to advice loan request");
        }
        loanRequest.setSendback(true);
        User auditUser = getHistoryUser(loanRequest, Constants.Bank_USER_ROLE);
        transferStatus(loanRequest, RequestStatus.bank_credit_audit, Phase.bank_credit_audit, auditUser, locale, loggedUser, Constants.CA_ROLE);
    }*/

    // sca decide -> master provider qualification audit
    protected void handleSubmitDecision(LoanRequest loanRequest, Locale locale, User loggedUser) throws AccessDeniedException, IllegalAccessException {
        if (log.isDebugEnabled()) {
            log.debug("Decide loan request " + loanRequest.getNumber());
        }

        if (!loanRequest.getAuditUser().hasRole(Constants.SCA_ROLE) || loanRequest.getPhase() != Phase.sca_audit) {
            throw new AccessDeniedException("You have no right to decide loan request");
        }
        loanRequest.setSendback(false);
        if (loanRequest.getAuditCode().equals(AuditCode.approve) || loanRequest.getAuditCode().equals(AuditCode.changeApprove)) {
            // get insurance user from dealer
            //User auditUser = loanRequest.getDealer().getMasterProvider().getBondUser();
            //transferStatus(loanRequest, RequestStatus.request_audit, Phase.qualification_audit, auditUser, locale, loggedUser, Constants.SCA_ROLE);
            handleAction(ACTION_scaApprove, loanRequest, locale, loggedUser);
        } else if (loanRequest.getAuditCode().equals(AuditCode.cancel)) {
            User auditUser = null;
            loanRequest.setDecideDate(new Date());
            transferStatus(loanRequest, RequestStatus.request_cancelled, Phase.request_cancelled, auditUser, locale, loggedUser, Constants.SCA_ROLE);
        } else if (loanRequest.getAuditCode().equals(AuditCode.deny)) {
            User auditUser = null;
            loanRequest.setDecideDate(new Date());
            transferStatus(loanRequest, RequestStatus.request_denied, Phase.request_denied, auditUser, locale, loggedUser, Constants.SCA_ROLE);
        }
    }

    // sca back to ca
    /*protected void handleBackToCA(LoanRequest loanRequest, Locale locale, User loggedUser) throws AccessDeniedException, IllegalAccessException {
        if (log.isDebugEnabled()) {
            log.debug("Decide loan request " + loanRequest.getNumber());
        }

        if (!loanRequest.getAuditUser().hasRole(Constants.SCA_ROLE) || loanRequest.getPhase() != Phase.sca_audit) {
            throw new AccessDeniedException("You have no right to decide loan request");
        }

        loanRequest.setSendback(true);
        User auditUser = getHistoryUser(loanRequest, Constants.CA_ROLE);
        transferStatus(loanRequest, RequestStatus.request_audit, Phase.ca_audit, auditUser, locale, loggedUser, Constants.SCA_ROLE);
    }*/

    // insurance qualification audit -> dealer
    /*protected void handleApproveQualification(LoanRequest loanRequest, Locale locale, User loggedUser) throws AccessDeniedException {
        if (log.isDebugEnabled()) {
            log.debug("approve qualification " + loanRequest.getNumber());
        }

        if (!loanRequest.getAuditUser().hasRole(Constants.Insurance_ROLE) || loanRequest.getPhase() != Phase.qualification_audit) {
            throw new AccessDeniedException("You have no right to approve qualification of loan request");
        }
        loanRequest.setSendback(false);
        User auditUser = null;

        transferStatus(loanRequest, RequestStatus.dealer_apply_loan, Phase.dealer_apply_loan, auditUser, locale, loggedUser, Constants.Insurance_ROLE);
    }*/

    // insurance qualification audit back t-> SCA
    /*protected void handleBackQualification(LoanRequest loanRequest, Locale locale, User loggedUser) throws AccessDeniedException, IllegalAccessException {
        if (log.isDebugEnabled()) {
            log.debug("back to SCA " + loanRequest.getNumber());
        }

        if (!loanRequest.getAuditUser().hasRole(Constants.Insurance_ROLE) || loanRequest.getPhase() != Phase.qualification_audit) {
            throw new AccessDeniedException("You have no right to approve qualification of loan request");
        }

        loanRequest.setSendback(true);
        User auditUser = getHistoryUser(loanRequest, Constants.SCA_ROLE);
        transferStatus(loanRequest, RequestStatus.request_audit, Phase.sca_audit, auditUser, locale, loggedUser, Constants.Insurance_ROLE);
    }*/

    // dealer apply loan -> bond
    /*protected void handleApplyLoan(LoanRequest loanRequest, Locale locale, User loggedUser) throws AccessDeniedException {
        if (log.isDebugEnabled()) {
            log.debug("Apply loan request " + loanRequest.getNumber());
        }

        if (loanRequest.getPhase() != Phase.dealer_apply_loan || !(isDealer(loggedUser))) {
            throw new AccessDeniedException("You have no right to apply loan request");
        }
        User auditUser = loanRequest.getDealer().getBond().getBondUser();
        transferStatus(loanRequest, RequestStatus.loan_audit, Phase.bond_loan_audit, auditUser, locale, loggedUser, Constants.DEALER_USER_ROLE);

        loanRequest.setSendback(false);
        if (loanRequest.getDealer().getBond().isAutoAudit()) {
            handleBondApproveLoan(loanRequest, locale, auditUser);
        }
    }*/

    // dealer cancel loan
    /*protected void handleCancelLoan(LoanRequest loanRequest, Locale locale, User loggedUser) throws AccessDeniedException {
        if (log.isDebugEnabled()) {
            log.debug("Apply loan request " + loanRequest.getNumber());
        }

        if (loanRequest.getPhase() != Phase.dealer_apply_loan || !(isDealer(loggedUser))) {
            throw new AccessDeniedException("You have no right to apply loan request");
        }

        loanRequest.setSendback(false);
        User auditUser = null;
        transferStatus(loanRequest, RequestStatus.loan_cancelled, Phase.loan_cancelled, auditUser, locale, loggedUser, Constants.DEALER_USER_ROLE);
    }*/

    // bond approve -> booking
    /*protected void handleBondApproveLoan(LoanRequest loanRequest, Locale locale, User loggedUser) throws AccessDeniedException {
        if (log.isDebugEnabled()) {
            log.debug("bond company approve loan " + loanRequest.getNumber());
        }

        if (loanRequest.getPhase() != Phase.bond_loan_audit || !loanRequest.getAuditUser().hasRole(Constants.Bond_USER_ROLE)) {
            throw new AccessDeniedException("You have no right to approve request");
        }

        loanRequest.setSendback(false);
        User auditUser = getRandomUser(Constants.Booking_ROLE);
        transferStatus(loanRequest, RequestStatus.loan_audit, Phase.booking_audit, auditUser, locale, loggedUser, Constants.Bond_USER_ROLE);
    }*/

    // bond deny
    /*protected void handleBondDenyLoan(LoanRequest loanRequest, Locale locale, User loggedUser) throws AccessDeniedException {
        if (log.isDebugEnabled()) {
            log.debug("bond company deny request " + loanRequest.getNumber());
        }

        if (loanRequest.getPhase() != Phase.bond_loan_audit || !loanRequest.getAuditUser().hasRole(Constants.Bond_USER_ROLE)) {
            throw new AccessDeniedException("You have no right to deny request");
        }

        loanRequest.setSendback(false);
        User auditUser = null;
        loanRequest.setDecideDate(new Date());
        transferStatus(loanRequest, RequestStatus.loan_denied, Phase.loan_denied, auditUser, locale, loggedUser, Constants.Bond_USER_ROLE);
    }*/

    // booking approve -> insurance
    /*protected void handleApproveLoanApply(LoanRequest loanRequest, Locale locale, User loggedUser) throws AccessDeniedException, IllegalAccessException {
        if (log.isDebugEnabled()) {
            log.debug("Approve loan apply request " + loanRequest.getNumber());
        }

        if (loanRequest.getPhase() != Phase.booking_audit || !loanRequest.getAuditUser().hasRole(Constants.Booking_ROLE)) {
            throw new AccessDeniedException("You have no right to approve loan apply request");
        }

        loanRequest.setSendback(false);
        //User auditUser = loanRequest.getLoanProduct().getBank().getBankUser();
        User auditUser = loanRequest.getDealer().getSlaveProvider().getBondUser();
        transferStatus(loanRequest, RequestStatus.loan_audit, Phase.insurance_loan_audit, auditUser, locale, loggedUser, Constants.Booking_ROLE);

        // slave auto audit
        if (loanRequest.getDealer().getSlaveProvider().isAutoAudit()) {
            handleApproveLoanBank(loanRequest, locale, loggedUser);
        }
    }*/

    // booking approve -> bank
    /*protected void handleGotoBankAudit(LoanRequest loanRequest, Locale locale, User loggedUser) throws AccessDeniedException, IllegalAccessException {
        if (log.isDebugEnabled()) {
            log.debug("Approve loan apply request " + loanRequest.getNumber());
        }

        if (loanRequest.getPhase() != Phase.booking_audit || !loanRequest.getAuditUser().hasRole(Constants.Booking_ROLE)) {
            throw new AccessDeniedException("You have no right to approve loan apply request");
        }

        loanRequest.setSendback(false);
        //User auditUser = loanRequest.getLoanProduct().getBank().getBankUser();
        User auditUser = getHistoryUser(loanRequest, Constants.Bank_USER_ROLE);
        transferStatus(loanRequest, RequestStatus.loan_audit, Phase.bank_loan_audit, auditUser, locale, loggedUser, Constants.Booking_ROLE);
    }*/

    // booking deny
    /*protected void handleDenyLoanApply(LoanRequest loanRequest, Locale locale, User loggedUser) throws AccessDeniedException {
        if (log.isDebugEnabled()) {
            log.debug("Deny loan apply request " + loanRequest.getNumber());
        }

        if (loanRequest.getPhase() != Phase.booking_audit || !loanRequest.getAuditUser().hasRole(Constants.Booking_ROLE)) {
            throw new AccessDeniedException("You have no right to deny loan apply");
        }

        loanRequest.setSendback(false);
        User auditUser = null;
        loanRequest.setDecideDate(new Date());
        transferStatus(loanRequest, RequestStatus.loan_denied, Phase.loan_denied, auditUser, locale, loggedUser, Constants.Booking_ROLE);
    }*/

    // insurance approve -> master insurance
    /*protected void handleApproveLoanBank(LoanRequest loanRequest, Locale locale, User loggedUser) throws AccessDeniedException, IllegalAccessException {
        if (log.isDebugEnabled()) {
            log.debug("Insurance Approve loan bank request " + loanRequest.getNumber());
        }

        if (loanRequest.getPhase() != Phase.insurance_loan_audit || !loanRequest.getAuditUser().hasRole(Constants.Insurance_ROLE)) {
            throw new AccessDeniedException("You have no right to approve loan bank request");
        }

        loanRequest.setSendback(false);
        //User auditUser = loanRequest.getLoanProduct().getBank().getBankUser();
        User auditUser = null; // pending bank to grab
        transferStatus(loanRequest, RequestStatus.loan_audit, Phase.pending_loan_material, auditUser, locale, loggedUser, Constants.Insurance_ROLE);
        loanRequest.setAuditUser(null); // bank grab ticket
    }*/

    // insurance upload cover -> bank
    /*protected void handleUploadCover(LoanRequest loanRequest, Locale locale, User loggedUser) throws AccessDeniedException, IllegalAccessException {
        if (log.isDebugEnabled()) {
            log.debug("Insurance upload cover " + loanRequest.getNumber());
        }

        if (loanRequest.getPhase() != Phase.insurance_upload_cover || !loanRequest.getAuditUser().hasRole(Constants.Insurance_ROLE)) {
            throw new AccessDeniedException("You have no right to upload cover");
        }

        loanRequest.setSendback(false);
        //User auditUser = loanRequest.getLoanProduct().getBank().getBankUser();
        User auditUser = getHistoryUser(loanRequest, Constants.Bank_USER_ROLE);
        transferStatus(loanRequest, RequestStatus.loan_audit, Phase.bank_loan_audit, auditUser, locale, loggedUser, Constants.Insurance_ROLE);
    }*/

    // insurance approve back -> booking
    /*protected void handleBackInsurance(LoanRequest loanRequest, Locale locale, User loggedUser) throws AccessDeniedException, IllegalAccessException {
        if (log.isDebugEnabled()) {
            log.debug("Insurance back to booking " + loanRequest.getNumber());
        }

        if (loanRequest.getPhase() != Phase.insurance_loan_audit || !loanRequest.getAuditUser().hasRole(Constants.Insurance_ROLE)) {
            throw new AccessDeniedException("You have no right to approve loan bank request");
        }

        User auditUser = getHistoryUser(loanRequest, Constants.Booking_ROLE);
        loanRequest.setSendback(true);
        transferStatus(loanRequest, RequestStatus.loan_audit, Phase.booking_audit, auditUser, locale, loggedUser, Constants.Insurance_ROLE);
    }*/

    // bank approve -> bank pending loan
    /*protected void handleApproveInsurance(LoanRequest loanRequest, Locale locale, User loggedUser) throws AccessDeniedException, IllegalAccessException {
        if (log.isDebugEnabled()) {
            log.debug("bank Approve loan request " + loanRequest.getNumber());
        }

        if (loanRequest.getPhase() != Phase.bank_loan_audit || !loanRequest.getAuditUser().hasRole(Constants.Bank_USER_ROLE)) {
            throw new AccessDeniedException("You have no right to approve insurance");
        }

        loanRequest.setSendback(false);
        User auditUser = loanRequest.getDealer().getSlaveProvider().getBondUser();
        transferStatus(loanRequest, RequestStatus.loan_audit, Phase.insurance_confirm_policy, auditUser, locale, loggedUser, Constants.Bank_USER_ROLE);

        // slave auto audit
        if (loanRequest.getDealer().getSlaveProvider().isAutoAudit()) {
            handleConfirmPolicy(loanRequest, locale, loggedUser);
        }
    }*/

    // bank approve back -> booking
    /*protected void handleBackBankAudit(LoanRequest loanRequest, Locale locale, User loggedUser) throws AccessDeniedException, IllegalAccessException {
        if (log.isDebugEnabled()) {
            log.debug("bank back to booking " + loanRequest.getNumber());
        }

        if (loanRequest.getPhase() != Phase.bank_loan_audit || !loanRequest.getAuditUser().hasRole(Constants.Bank_USER_ROLE)) {
            throw new AccessDeniedException("You have no right to approve insurance");
        }

        User auditUser = getHistoryUser(loanRequest, Constants.Booking_ROLE);
        loanRequest.setSendback(true);
        transferStatus(loanRequest, RequestStatus.loan_audit, Phase.booking_audit, auditUser, locale, loggedUser, Constants.Bank_USER_ROLE);
    }*/

    // insurance confirm policy -> insurance
    /*protected void handleConfirmPolicy(LoanRequest loanRequest, Locale locale, User loggedUser) throws AccessDeniedException, IllegalAccessException {
        if (log.isDebugEnabled()) {
            log.debug("insurance confirm policy " + loanRequest.getNumber());
        }

        if (loanRequest.getPhase() != Phase.insurance_confirm_policy || !loanRequest.getAuditUser().hasRole(Constants.Insurance_ROLE)) {
            throw new AccessDeniedException("You have no right to confirm policy");
        }

        loanRequest.setSendback(false);
        User auditUser = loanRequest.getDealer().getMasterProvider().getBondUser();
        transferStatus(loanRequest, RequestStatus.loan_audit, Phase.insurance_upload_policy, auditUser, locale, loggedUser, Constants.Insurance_ROLE);
    }*/

    // insurance upload policy -> end
    /*protected void handleUploadPolicy(LoanRequest loanRequest, Locale locale, User loggedUser) throws AccessDeniedException, IllegalAccessException {
        if (log.isDebugEnabled()) {
            log.debug("insurance upload policy " + loanRequest.getNumber());
        }

        if (loanRequest.getPhase() != Phase.insurance_upload_policy || !loanRequest.getAuditUser().hasRole(Constants.Insurance_ROLE)) {
            throw new AccessDeniedException("You have no right to upload policy");
        }

        loanRequest.setSendback(false);
        //User auditUser = loanRequest.getLoanProduct().getBank().getBankUser();
        User auditUser = getHistoryUser(loanRequest, Constants.Bank_USER_ROLE);
        transferStatus(loanRequest, RequestStatus.loan_audit, Phase.bank_pending_loan, auditUser, locale, loggedUser, Constants.Insurance_ROLE);
    }*/

    // pending loaned -> loaned -> insurance
    /*protected void handleBankLoaned(LoanRequest loanRequest, Locale locale, User loggedUser) throws AccessDeniedException, IllegalAccessException {
        if (log.isDebugEnabled()) {
            log.debug("bank loaned " + loanRequest.getNumber());
        }

        if (loanRequest.getPhase() != Phase.bank_pending_loan || !loanRequest.getAuditUser().hasRole(Constants.Bank_USER_ROLE)) {
            throw new AccessDeniedException("You have no right to loan");
        }

        loanRequest.setSendback(false);
        User auditUser = null;
        transferStatus(loanRequest, RequestStatus.loan_approved, Phase.loan_approved, auditUser, locale, loggedUser, Constants.Bank_USER_ROLE);
    }*/

    protected void handleBatchReceive(LoanRequest loanRequest, Long[] selectedIds, User loginUser){
        /*for (Long id : selectedIds) {
            for (Attachment attachment : loanRequest.getAttachmentList()) {
                if (attachment.getId().equals(id)) {
                    attachment.setAllReceived(true);
                    attachment.setReceiveOperator(loginUser.getUsername());
                    attachment.setReceiveDate(new Date());
                }
            }
        }

        // check if loan material complete
        boolean loanComplete = true;
        LoanProduct loanProduct = loanProductManager.loadLoanProduct(loanRequest.getLoanProduct().getId());
        List<String> loanMeterialNames = loanProduct.getLoanMaterialNames();
        for (String materialName : loanMeterialNames) {
            for (Attachment attachment : loanRequest.getAttachmentList()) {
                if (attachment.getName().equals(materialName)) {
                    if (!attachment.isAllReceived()) {
                        loanComplete = false;
                    }
                }
            }
        }

        boolean allReceived = true;
        for (Attachment attachment : loanRequest.getAttachmentList()) {
            if (!attachment.isAllReceived()) {
                allReceived = false;
            }
        }
        loanRequest.setAllReceived(allReceived);

        if (loanComplete) { // go to next flow
            loanRequest.setPhase(Phase.bank_loan_audit);
        }*/

    }


    private boolean isDealer(User user) {
        return user.hasRole(Constants.DEALER_USER_ROLE);
    }
    /**************************************************************************************************************************************
     handle process flow and status transition  END
     **************************************************************************************************************************************/

    protected void sendMessageForRule(final LoanRequest loanRequest) {
        try {
            jmsTemplate.send(destination, new MessageCreator() {
                @Override
                public Message createMessage(Session session) throws JMSException {
                    Message message = session.createMessage();
                    message.setLongProperty("reqId", loanRequest.getId());
                    message.setStringProperty("type", Constants.MSG_TYPE_RULE);
                    return message;
                }
            });
        } catch(JmsException ex) {
            log.error("can't send jms message to destination: " + destination);
        }
    }

    protected void sendConfirmCoverMessageForMessage(final LoanRequest loanRequest) {
        try {
            jmsTemplate.send(destination, new MessageCreator() {
                @Override
                public Message createMessage(Session session) throws JMSException {
                    Message message = session.createMessage();
                    message.setLongProperty("reqId", loanRequest.getId());
                    message.setIntProperty("times", 1);
                    message.setStringProperty("type", Constants.MSG_TYPE_MESSAGE_CONFIRM_COVER);
                    return message;
                }
            });
        } catch(JmsException ex) {
            log.error("can't send jms message to destination: " + destination);
        }
    }

    protected void sendQualificationAuditMessageForMessage(final LoanRequest loanRequest) {
        try {
            jmsTemplate.send(destination, new MessageCreator() {
                @Override
                public Message createMessage(Session session) throws JMSException {
                    Message message = session.createMessage();
                    message.setLongProperty("reqId", loanRequest.getId());
                    message.setStringProperty("type", Constants.MSG_TYPE_MESSAGE_QUALIFICATION_AUDIT);
                    return message;
                }
            });
        } catch(JmsException ex) {
            log.error("can't send jms message to destination: " + destination);
        }
    }

    protected void sendPolicyMessageForMessage(final LoanRequest loanRequest) {
        try {
            jmsTemplate.send(destination, new MessageCreator() {
                @Override
                public Message createMessage(Session session) throws JMSException {
                    Message message = session.createMessage();
                    message.setLongProperty("reqId", loanRequest.getId());
                    message.setStringProperty("type", Constants.MSG_TYPE_MESSAGE_UPLOAD_POLICY);
                    return message;
                }
            });
        } catch(JmsException ex) {
            log.error("can't send jms message to destination: " + destination);
        }
    }

    protected void sendDelayedMessageForAudit(final LoanRequest loanRequest) {
        // check if after 15:00
        Date auditDate = loanRequest.getAuditDate();
        if (auditDate == null)
            return;

        Calendar auditCalendar = Calendar.getInstance();
        auditCalendar.setTime(auditDate);

        Date currentDate = new Date();
        Calendar currentCalendar = Calendar.getInstance();
        currentCalendar.setTime(currentDate);

        // go to next day's 10AM
        Date nextDate = new Date();
        Calendar nextCalendar = Calendar.getInstance();
        nextCalendar.setTime(nextDate);
        nextCalendar.roll(Calendar.DATE, 1);
        nextCalendar.set(Calendar.HOUR_OF_DAY, 10);

        long time = 0L;

        int hour = auditCalendar.get(Calendar.HOUR_OF_DAY);
        if (hour <= 15) {
            auditCalendar.roll(Calendar.HOUR_OF_DAY, 6);
            time = auditCalendar.getTime().getTime() - currentDate.getTime();
        } else {
            time = nextCalendar.getTime().getTime() - currentDate.getTime();
        }
        sendDelayedMessageForAudoAudit(loanRequest, time);
    }

    private void sendDelayedMessageForAudoAudit(final LoanRequest loanRequest, long time) {
        jmsTemplate.setDeliveryMode(DeliveryMode.PERSISTENT);
        try {
            jmsTemplate.send(destination, new MessageCreator() {
                @Override
                public Message createMessage(Session session) throws JMSException {
                    Message message = session.createMessage();

                    message.setLongProperty(ScheduledMessage.AMQ_SCHEDULED_DELAY, time);
                    message.setLongProperty("reqId", loanRequest.getId());
                    message.setStringProperty("type", Constants.MSG_TYPE_AUTO_AUDIT);
                    return message;
                }
            });
        } catch(JmsException ex) {
            log.error("can't send jms message to destination: " + destination);
        }
    }

    protected User getHistoryUser(LoanRequest loanRequest, String role) throws IllegalAccessException {
        User auditUser;
        String username = null;
        List<Activity> activities = loanRequest.getActivities();
        for (int i = activities.size()-1; i >= 0; i--) {
            Activity activity = activities.get(i);
            if (activity.getRole().equals(role)) {
                username = activity.getOperator();
                break;
            }
        }
        if (username != null) {
            auditUser = userManager.getUserByUsername(username);
        } else {
            throw new IllegalAccessException("request not processed by any " + role);
        }
        return auditUser;
    }


    protected Action getAction(LoanRequest loanRequest, User loginUser, HttpServletRequest httpServletRequest) {
        com.yygo.configentity.action.Phase rolePhase = getRolePhase(loanRequest, loginUser);
        for (Action action : rolePhase.getActions()) {
            if (httpServletRequest.getParameter(action.getName()) != null) {
                return action;
            }
        }
        return null;
    }

    protected Action getAction(LoanRequest loanRequest, User loginUser, String actionName) {
        com.yygo.configentity.action.Phase rolePhase = getRolePhase(loanRequest, loginUser);
        for (Action action : rolePhase.getActions()) {
            if (actionName.equals(action.getName())) {
                return action;
            }
        }
        return null;
    }

    //@ModelAttribute("phaseInfo")
    protected com.yygo.configentity.action.Phase getPhaseInfo(@RequestParam(required = false, value = "reqId") Long reqId, Principal principal){
        User loginUser = userManager.getUserByUsername(principal.getName());
        LoanRequest loanRequest = loanRequestManager.get(reqId);

        return getRolePhase(loanRequest, loginUser);
    }

    protected com.yygo.configentity.action.Phase getRolePhase(LoanRequest loanRequest, User loginUser) {
        com.yygo.configentity.action.Phase rolePhase = null;
        String phaseStr = loanRequest.getPhase().toString();
        for (Role role : loginUser.getRoles()) {
            rolePhase = roleActionsConfigurer.getRoleAction(role.getName(), phaseStr);
            if (rolePhase != null) {
                break;
            }
        }

        return rolePhase;
    }

    protected RoleFeedback getRoleFeedback(LoanRequest loanRequest, User loginUser) {
        RoleFeedback roleFeedback = null;
        String phaseStr = loanRequest.getPhase().toString();
        for (Role role : loginUser.getRoles()) {
            roleFeedback = roleFeedbacksConfigurer.getRoleFeedbacks(role.getName(), phaseStr);
            if (roleFeedback != null) {
                break;
            }
        }

        return roleFeedback;
    }

    //@ModelAttribute("viewInfo")
    protected com.yygo.configentity.view.RoleView getViewInfo(@RequestParam(required = false, value = "reqId") Long reqId, Principal principal){
        User loginUser = userManager.getUserByUsername(principal.getName());
        LoanRequest loanRequest = loanRequestManager.get(reqId);

        com.yygo.configentity.action.Phase rolePhase = getRolePhase(loanRequest, loginUser);

        String phaseStr = loanRequest.getPhase().toString();
        com.yygo.configentity.view.RoleView roleView = roleViewsConfigurer.getPhase(rolePhase.getRole(), phaseStr);

        return roleView;
    }

    protected RoleAttachment getAttachmentInfo(LoanRequest loanRequest, User loginUser) {
        for (Role role : loginUser.getRoles()) {
            RoleAttachment roleAttachment = roleAttachmentsConfigurer.getPhase(role.getName(), loanRequest.getPhase().toString(), loanRequest.getStatus().toString());
            if (roleAttachment != null) {
                return roleAttachment;
            }
        }
        return null;
    }

    @ModelAttribute("loanProducts")
    protected List<LabelValue> getLoanProductsByBank(@RequestParam(required = false, value = "reqId") Long reqId, Principal principal) {
        User loginUser = userManager.getUserByUsername(principal.getName());
        Dealer dealer = loginUser.getDealer();

        boolean second = false;
        if (dealer == null && reqId != null) {
            LoanRequest loanRequest = loanRequestManager.get(reqId);
            dealer = loanRequest.getDealer();
            second = loanRequest.isSecond();
        }

        List<LabelValue> list = new ArrayList<LabelValue>();
        if (dealer != null) {
            if (dealer != null) {
                BondCompany bond = dealer.getBond();
                if (bond != null) {
                    List<LoanProduct> loanProducts = loanProductManager.getLoanProductsByBond(bond.getId(), second);
                    for (LoanProduct loanProduct : loanProducts) {
                        if (loanProduct.isEnabled()) {
                            list.add(new LabelValue(loanProduct.getProductName(), "" + loanProduct.getId()));
                        }
                    }
                }

            }
        }
        return list;
    }

    @ModelAttribute("availableProvinces")
    protected List<LabelValue> getAvailableProvinces() {
        List<LabelValue> list = new ArrayList<LabelValue>();
        List<Province> provinces = provinceManager.getAll();
        for (Province province : provinces) {
            list.add(new LabelValue(province.getName(), province.getName()));
        }
        return list;
    }

    @ModelAttribute("availableBrands")
    protected List<LabelValue> getAvailableBrands(@RequestParam(required = false, value = "reqId") Long reqId) {
        boolean second = false;
        if (reqId != null) {
            LoanRequest loanRequest = loanRequestManager.get(reqId);
            second = loanRequest.isSecond();
        }
        List<LabelValue> list = new ArrayList<LabelValue>();
        List<VehicleBrand> vehicleBrands = vehicleBrandManager.getAllBrands(second);
        for (VehicleBrand province : vehicleBrands) {
            list.add(new LabelValue(province.getBrand(), province.getBrand()));
        }
        return list;
    }

    @Autowired
    private CertificateManager certificateManager;

    @ModelAttribute("addressCertificates")
    protected  List<LabelValue> getAddressCertificates() {
        return getCertificates("Address");
    }

    @ModelAttribute("incomeCertificates")
    protected  List<LabelValue> getIncomeCertificates() {
        return getCertificates("Income");
    }

    @ModelAttribute("driveCertificates")
    protected  List<LabelValue> getDriveCertificates() {
        return getCertificates("Drive");
    }

    @ModelAttribute("identityCertificates")
    protected  List<LabelValue> getIdentityCertificates() {
        return getCertificates("Identity");
    }

    private List<LabelValue> getCertificates(String key) {
        List<LabelValue> list = new ArrayList<LabelValue>();
        String type = getText("CERTIFICATE_TYPE_" + key, LocaleContextHolder.getLocale());
        List<Certificate> certificates = certificateManager.getCertificatesByType(type);
        for (Certificate certificate : certificates) {
            list.add(new LabelValue(certificate.getName(), certificate.getName()));
        }
        return list;
    }

    @ModelAttribute("availableGenders")
    protected List<LabelValue> loadAvailableGenders() {
        return getList(Constants.GENDER);
    }

    @ModelAttribute("availableMaritalStatus")
    protected List<LabelValue> loadAvailableMaritalStatus() {
        return getList(Constants.MARITAL_STATUS);
    }

    @ModelAttribute("availableRequestStatus")
    protected List<LabelValue> loadAvailableRequestStatus() {
        return getList(Constants.REQUEST_STATUS);
    }

    @ModelAttribute("availableFeedbackStatus")
    protected List<LabelValue> loadAvailableFeedbackStatus() {
        return getList(Constants.FEEDBACK_STATUS);
    }

    @ModelAttribute("availableCompanyNatures")
    protected List<LabelValue> loadAvailableCompanyNatures() {
        return getList(Constants.COMPANY_NATURE);
    }

    @ModelAttribute("availableIndustryTypes")
    protected List<LabelValue> loadAvailableIndustryTypes() {
        return getList(Constants.INDUSTRY_TYPE);
    }

    @ModelAttribute("availableIdTypes")
    protected List<LabelValue> loadAvailableIdTypes() {
        return getList(Constants.ID_TYPE);
    }

    @ModelAttribute("availableLoanTypes")
    protected List<LabelValue> loadAvailableLoanTypes() {
        return getList(Constants.LOAN_TYPE);
    }

    @ModelAttribute("availableLoanYears")
    protected List<LabelValue> loadAvailableLoanYears() {
        return getList(Constants.LOAN_YEARS);
    }

    @ModelAttribute("availableMailTypes")
    protected List<LabelValue> loadAvailableMailTypes() {
        return getList(Constants.MAIL_TYPE);
    }

    @ModelAttribute("availablePropertyTypes")
    protected List<LabelValue> loadAvailablePropertyTypes() {
        return getList(Constants.PROPERTY_TYPE);
    }

    @ModelAttribute("availableWorkPositions")
    protected List<LabelValue> loadAvailableWorkPositions() {
        return getList(Constants.WORK_POSITION);
    }

    @ModelAttribute("availableEducationLevel")
    protected List<LabelValue> loadEducationLevel() {return getList(Constants.EDUCATION_LEVEL); }

    @ModelAttribute("availableOccupation")
    protected List<LabelValue> loadOccupation() {return getList(Constants.OCCUPATION_TYPE); }


}
